package com.campusbook.aop;

import com.campusbook.model.User;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 系统操作日志切面
 * 演示Spring AOP的使用
 */
@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    /**
     * 定义切点：所有Controller层的方法
     */
    @Pointcut("execution(* com.campusbook.controller.*.*(..))")
    public void controllerLayer() {}

    /**
     * 定义切点：所有Service层的方法
     */
    @Pointcut("execution(* com.campusbook.service.*.*(..))")
    public void serviceLayer() {}

    /**
     * 前置通知：记录方法调用信息
     */
    @Before("controllerLayer() || serviceLayer()")
    public void logMethodCall(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        logger.info("调用方法: {}.{}() 参数: {}", 
            joinPoint.getTarget().getClass().getSimpleName(),
            method.getName(),
            Arrays.toString(joinPoint.getArgs())
        );
        
        // 记录当前用户信息
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.getPrincipal() instanceof User) {
            User user = (User) auth.getPrincipal();
            logger.info("当前用户: {}", user.getUsername());
        }
    }

    /**
     * 后置通知：记录方法返回信息
     */
    @AfterReturning(pointcut = "controllerLayer() || serviceLayer()", returning = "result")
    public void logMethodReturn(JoinPoint joinPoint, Object result) {
        logger.info("方法返回: {}.{}() 返回值: {}", 
            joinPoint.getTarget().getClass().getSimpleName(),
            joinPoint.getSignature().getName(),
            result != null ? result.toString() : "null"
        );
    }

    /**
     * 异常通知：记录方法异常信息
     */
    @AfterThrowing(pointcut = "controllerLayer() || serviceLayer()", throwing = "exception")
    public void logMethodException(JoinPoint joinPoint, Exception exception) {
        logger.error("方法异常: {}.{}() 异常: {}", 
            joinPoint.getTarget().getClass().getSimpleName(),
            joinPoint.getSignature().getName(),
            exception.getMessage(),
            exception
        );
    }

    /**
     * 环绕通知：计算方法执行时间
     */
    @Around("controllerLayer()")
    public Object logExecutionTime(org.aspectj.lang.ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        
        try {
            Object result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            
            logger.info("执行时间: {}.{}() 耗时: {}ms", 
                className, methodName, executionTime);
            
            return result;
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            logger.error("异常时间: {}.{}() 耗时: {}ms 异常: {}", 
                className, methodName, executionTime, e.getMessage());
            throw e;
        }
    }
}
